# This file is part of OrangeSpider. OrangeSpider is a meta model based
# development tool.
# 
# OrangeSpider is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# OrangeSpider is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with OrangeSpider.  If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2009 Stefan Nikolaus <OrangeSpiderMaster@googlemail.com>

from MetaModel import *
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import Component
from Types import *


class HexEdit(QTextEdit):
    AllowedChars = [Qt.Key_0, Qt.Key_1, Qt.Key_2, Qt.Key_3, Qt.Key_4,
                    Qt.Key_5, Qt.Key_6, Qt.Key_7, Qt.Key_8, Qt.Key_9,
                    Qt.Key_A, Qt.Key_B, Qt.Key_C, Qt.Key_D, Qt.Key_E, Qt.Key_F]
    AllowedNavigation = [ Qt.Key_Home, Qt.Key_End, 
                          Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down ]
    AllowedKeys = AllowedNavigation + AllowedChars

    def __init__(self, parent = None):
        QTextEdit.__init__(self, parent)
        font = QFont("Courier New", 10)
        self.setFont(font)
        self.data = ""
        self.setOverwriteMode(True)

    def setData(self, s):
        s2 = ""
        count = 0
        for c in s:
            s2 += "%02x " % ord(c)
            count += 1
            if count % 16 == 0:
                s2 += "\n"
        self.setText(s2)
        self.data = s

    def getData(self):
        s = str(self.toPlainText())
        s = s.replace("\n", " ")
        l = s.split(" ")
        newData = ""
        count = 0
        for c in l:
            if c:
                newData += chr(int(c, 16))
                count += 1
        return newData

    def keyPressEvent(self, event):
        if event.key() in HexEdit.AllowedChars:
            cn = self.textCursor().columnNumber() 
            if cn > 46:
                event.ignore()
                return
            c = cn % 3
            if c == 0:
                QTextEdit.keyPressEvent(self, event)
                return
            elif c == 1:
                QTextEdit.keyPressEvent(self, event)
                self.moveCursor(QTextCursor.Right)
                return
            elif c == 2:
                return

        if event.key() in HexEdit.AllowedNavigation:
            QTextEdit.keyPressEvent(self, event)
            c = self.textCursor().columnNumber() % 3
            if event.key() == Qt.Key_Left:
                if c == 2:
                    self.moveCursor(QTextCursor.Left)
            elif event.key() == Qt.Key_Right:
                if c == 2:
                    self.moveCursor(QTextCursor.Right)
            return
        event.ignore()

    def setLength(self, newLength):
        data = self.getData()
        currentLength = len(data)
        if currentLength > newLength:
            data = data[0:newLength]
            self.setData(data)
        elif currentLength < newLength:
            data = data + '\0' * (newLength - currentLength)
            self.setData(data)

def _getFilenameFromDropEvent(event):
    md = event.mimeData()
    if md.hasUrls():
        urls = md.urls()
        if len(urls):
            s = str(urls[0].toLocalFile())
            return s
    return ""


"""
Pickers for the Selector
"""    
class PictureDlg(QDialog):
    def __init__(self, parent = None):
        QDialog.__init__(self, parent)
        self.setWindowTitle("Picture")
        self.ly = QVBoxLayout()
        self.lbl = QLabel()
        self.ly.addWidget(self.lbl)
        self.lblSize = QLabel()
        self.ly.addWidget(self.lblSize)
        self.setLayout(self.ly)

        self.resize(100, 100)
        self.setAcceptDrops(1)
        self.setWindowIcon(QIcon("img/spiderIco.png"))

    def action(self):
        self.exec_()
    def setEditorData(self, value):
        s = value
        pixmap = QPixmap()
        pixmap.loadFromData(s, "PNG")         
        self._setPicture(pixmap)

    def getEditorData(self):
        s = ""
        bytes = QByteArray()
        buffer = QBuffer(bytes)
        buffer.open(QIODevice.WriteOnly)
        pixmap = self.lbl.pixmap()
        pixmap.save(buffer, "PNG")
        s = str(bytes.data())
        return s

    def dragEnterEvent(self, event):
        event.accept()
    def dropEvent(self, event):
        s = _getFilenameFromDropEvent(event)
        if s:
            pixmap = QPixmap(s)
            self._setPicture(pixmap)


    def _setPicture(self, pix):
        self.lbl.setPixmap(pix)
        size = pix.size()
        if size.isValid():
            sizeStr = "Size %d x %d" % (size.width(), size.height())
        else:
            sizeStr = "no picture"
        self.lblSize.setText(sizeStr)


class DataDlg(QDialog):
    def __init__(self, parent = None):
        QDialog.__init__(self, parent)
        self.setWindowTitle("Data")
        self.ly = QVBoxLayout()
        ly2 = QHBoxLayout()
        self.lbl = QLabel("Size")
        ly2.addWidget(self.lbl)
        self.sizeEdit = QSpinBox()
        self.sizeEdit.setMaximum(32768)
        ly2.addWidget(self.sizeEdit)
        ly2.addStretch()
        self.ly.addLayout(ly2)

        self.hexEdit = HexEdit()
        self.ly.addWidget(self.hexEdit)
        self.setLayout(self.ly)
        self.resize(500, 300)

        self.connect(self.sizeEdit, SIGNAL("valueChanged(int)"),
                     self.hexEdit.setLength)
        self.setWindowIcon(QIcon("img/spiderIco.png"))
        
    def action(self):
        self.exec_()

    def setEditorData(self, value):
        s = value
        self.hexEdit.setData(s)
        self.sizeEdit.setValue(len(s))

    def getEditorData(self):
        return self.hexEdit.getData()
    
class TextDlg(QDialog):
    def __init__(self, parent = None):
        QDialog.__init__(self, parent)
        self.setWindowTitle("Text")
        self.ly = QVBoxLayout()
        self.txt = QTextEdit()
        self.ly.addWidget(self.txt)
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.connect(self.buttonBox, SIGNAL("accepted()"), 
                     self.accept)
        self.connect(self.buttonBox, SIGNAL("rejected()"), 
                     self.reject)
        self.ly.addWidget(self.buttonBox)        
        self.ly.setSpacing(0)
        self.ly.setContentsMargins(0,0,0,0)
        self.setLayout(self.ly)
        self.resize(300, 200)
        self.setWindowIcon(QIcon("img/spiderIco.png"))

    def action(self):
        self.exec_()
    def setEditorData(self, value):
        self.txt.setText(value)
    def getEditorData(self):
        return str(self.txt.toPlainText())

class FilePicker:
    def __init__(self, parent = None):
        self.parent = parent
        self.fileName = ""
    def action(self):
        self.fileName = QFileDialog.getOpenFileName(self.parent,
           "Open Image", self.fileName, "Files (*.*)")
    def setEditorData(self, value):
        self.fileName = value
    def getEditorData(self):
        return self.fileName

class DirectoryPicker:
    def __init__(self, parent = None):
        self.parent = parent
        self.directoryName = ""
    def action(self):
        self.directoryName = QFileDialog.getExistingDirectory(self.parent, 
             "Open Directory", self.directoryName,
             QFileDialog.ShowDirsOnly)
    def setEditorData(self, value):
        self.directoryName = value
    def getEditorData(self):
        return self.directoryName

class ColorPicker:
    def __init__(self, parent = None):
        self.parent = parent
        self.color = QColor()
    def action(self):
        self.color = QColorDialog.getColor(self.color, self.parent)

    def setEditorData(self, value):
        v = value
        self.color.setRed(v[0])
        self.color.setGreen(v[1])
        self.color.setBlue(v[2])
        self.color.setAlpha(v[3])
    def getEditorData(self):
        v = (self.color.red(), self.color.green(), 
             self.color.blue(), self.color.alpha())
        return v

class FontPicker:
    def __init__(self, parent = None):
        self.parent = parent
        self.font = QFont()
    def action(self):
        ok = 0
        t = QFontDialog.getFont(self.font, self.parent)
        if t[1]:
            self.font = t[0]
    def setEditorData(self, value):
        self.font.setFamily(value)
    def getEditorData(self):
        return str(self.font.family())


"""
Collection of editors for the table views
"""
class Selector(QWidget):
    def __init__(self, picker, parent = None):
        QWidget.__init__(self, parent)
        self.picker = picker
        self.ly = QHBoxLayout()
        self.lineEdit = QLineEdit()
        self.ly.addWidget(self.lineEdit)
        self.button = QPushButton("...")
        self.ly.addWidget(self.button)
        self.ly.setSpacing(0)
        self.ly.setContentsMargins(0,0,0,0)
        self.setLayout(self.ly)
        self.button.setMaximumSize(QSize(20,20))
        self.connect(self.button, SIGNAL("clicked()"),
                     self.picker.action)
    def setEditorData(self, value):
        self.picker.setEditorData(value)
    def getEditorData(self):
        return self.picker.getEditorData()

class TupleEdit(QLineEdit):
    def __init__(self, tupleSize, parent = None):
        QLineEdit.__init__(self, parent)
    def setEditorData(self, value):
        v = value
        sep = ""
        s = ""
        for i in v:
           s = s + sep + str(i)
           sep = ", "
        self.setText(s)
        
    def getEditorData(self):
        v = str(self.text())
        v = v.split(",")
        v = tuple([float(c) for c in v])
        return v

class DateTimeEdit(QDateTimeEdit):
    def __init__(self, parent = None):
        QDateTimeEdit.__init__(self, parent)
    def setEditorData(self, value):
        v = value
        if isinstance(v, tuple):
            v = (2000, 1, 1, 0, 0, 0)

            d = QDate(v[0], v[1], v[2])
            t = QTime(v[3], v[4], v[5])
            self.setTime(t)
            self.setDate(d)
    def getEditorData(self):
        t = self.time()
        d = self.date()
        v = (d.year(), d.month(), d.day(), t.hour(), t.minute(), t.second())
        return v

class SpinBox(QSpinBox):
    def __init__(self, parent = None):
        QSpinBox.__init__(self, parent)
        self.setRange(- sys.maxint + 1, sys.maxint)
    def setEditorData(self, value):
        self.setValue(int(value))
    def getEditorData(self):
        return self.value()

class DoubleSpinBox(QDoubleSpinBox):
    def __init__(self, parent = None):
        QDoubleSpinBox.__init__(self, parent)
        self.setRange(- sys.maxint - 1, sys.maxint)
    def setEditorData(self, value):
        self.setValue(value)
    def getEditorData(self):
        return self.value()

class LineEdit(QLineEdit):
    def __init__(self, parent = None):
        QLineEdit.__init__(self, parent)
    def setEditorData(self, value):
        self.setText(value)
    def getEditorData(self):
        return str(self.text())

class CheckBox(QCheckBox):
    def __init__(self, parent = None):
        QCheckBox.__init__(self, parent)
    def setEditorData(self, value):
        if value:
           self.setChecked(True)
        else:
           self.setChecked(False)
    def getEditorData(self):
        return self.isChecked()


class Emitter(QObject):
    def __init__(self):
        QObject.__init__(self)
    def propertyChanged(self, object, key, oldValue, newValue):
        self.emit(SIGNAL("propertyChanged"), object, key, oldValue, newValue)
    def entityCreated(self, object):
        self.emit(SIGNAL("entityCreated"), object)
    def entityDeleted(self, object):
        self.emit(SIGNAL("entityDeleted"), object)


class Delegate(QItemDelegate):
    def __init__(self, table, parent = None):
        QItemDelegate.__init__(self, parent)
        self.table = table

    def createEditor(self, parent, option, index):
        ownEditor = 0

        # only special editors for assoc and class view
        if (Entity.CLASS != self.table.viewDesc[0] and
            Entity.ASSOC != self.table.viewDesc[0]):
            return QItemDelegate.createEditor(self, parent, option, index)
        if self.table._isExtendRow(index.row()):
            return QItemDelegate.createEditor(self, parent, option, index)

        (header, item, mp, ownEditor) = self._getItem(index)
        if ownEditor:
            if mp.metaType.isMetaEnum():
                editor = EnumComboBox(item, header, parent)
                return editor
            elif mp.metaType["Name"] == "String":
                return LineEdit(parent)
            elif mp.metaType["Name"] == "Integer":
                return SpinBox(parent)
            elif mp.metaType["Name"] == "Boolean":
                return CheckBox(parent)
            elif mp.metaType["Name"] == "Float":
                return DoubleSpinBox(parent)
            elif mp.metaType["Name"] == "Picture":
                return Selector(PictureDlg(parent), parent)
            elif mp.metaType["Name"] == "Text":
                return Selector(TextDlg(parent), parent)
            elif mp.metaType["Name"] == "DateTime":
                return DateTimeEdit(parent)
            elif mp.metaType["Name"] == "TimeStamp":
                return DateTimeEdit(parent)
            elif mp.metaType["Name"] == "Color":
                return Selector(ColorPicker(parent), parent)
            elif mp.metaType["Name"] == "Font":
                return Selector(FontPicker(parent), parent)
            elif mp.metaType["Name"] == "Blob":
                return Selector(DataDlg(parent), parent)
            elif mp.metaType["Name"] == "FileString":
                return Selector(FilePicker(parent), parent)
            elif mp.metaType["Name"] == "Directory":
                return Selector(DirectoryPicker(parent), parent)
            elif mp.metaType["Name"] == "Size":
                return TupleEdit(2, parent)
            elif mp.metaType["Name"] == "Point":
                return TupleEdit(2, parent)
            elif mp.metaType["Name"] == "Rect":
                return TupleEdit(4, parent)
            elif mp.metaType["Name"] == "Flags":
                return SpinBox(parent)
            elif mp.metaType["Name"] == "Url":
                return LineEdit(parent)
            else:
                assert(0)

        return QItemDelegate.createEditor(self, parent, option, index)

    def setEditorData(self, editor, index):
        (header, item, mp, ownEditor) = self._getItem(index)
        if ownEditor:
            if mp:
                editor.setEditorData(item[mp["Name"]])
        else:
            QItemDelegate.setEditorData(self, editor, index)
    
    def setModelData(self, editor, model, index):
        (header, item, mp, ownEditor) = self._getItem(index)
        if ownEditor:
            data = editor.getEditorData()
            model.setData(index, data, Qt.EditRole)
            editor.hide()
        else:
            QItemDelegate.setModelData(self, editor, model, index)

    def updateEditorGeometry(self, editor, option, index):
        QItemDelegate.updateEditorGeometry(self, editor, option, index)

    def _getItem(self, index):
        header = ""
        item = None
        mp = None
        ownEditor = 0
        if self.table._isExtendRow(index.row()):
            return ("", None, None, 0)
        if self.table.navigator == "Extension":
            header = self.table.headers[index.column()]
            item = index.internalPointer()
            if item:
                mp = item.intention.metaProperties[header]
            ownEditor = 1
        elif (self.table.navigator == "Incoming" or
            self.table.navigator == "Outgoing"):
            header = self.table.headers[index.column()]
            item = index.internalPointer()
            if item:
                mp = item.intention.metaProperties[header]
            ownEditor = 1
        elif self.table.navigator == "OutgoingClasses":
            header = self.table.headers[index.column()]
            item = index.internalPointer().target
            if item:
                mp = item.intention.metaProperties[header]
            ownEditor = 1
        elif self.table.navigator == "IncomingClasses":
            header = self.table.headers[index.column()]
            item = index.internalPointer().source
            if item:
                mp = item.intention.metaProperties[header]
            ownEditor = 1
        elif self.table.navigator == "Properties":
            row = index.row()
            header = self.table.keys[row]
            item = self.table.root
            if item:
                mp = item.intention.metaProperties[header]
            ownEditor = 1
        return (header, item, mp, ownEditor)

class Table(QObject):
    DataFromSource = 1
    DataFromTarget = 2
    DataFromEntity = 3

    ModeView = 0
    ModeEdit = 1
    ModeExtend = 2

    ViewDataRole = Qt.UserRole
    KeyDataRole = Qt.UserRole + 1

    viewDescTable = { 
        # Root Type        Navigator            Viewed Type          Key Type             Id      Data Selection
        (Entity.METAMODEL, "MetaClasses")    : (Entity.METACLASS,    Entity.METACLASS,    "Name", DataFromEntity),
        (Entity.METAMODEL, "MetaAssocs")     : (Entity.METAASSOC,    Entity.METAASSOC,    "Name", DataFromEntity),
        (Entity.METAMODEL, "MetaTypes")      : (Entity.METATYPE,     Entity.METATYPE,     "Name", DataFromEntity),
        (Entity.METAENUM,  "MetaAtoms")      : (Entity.METAATOM,     Entity.METAATOM,     "Name", DataFromEntity),
        (Entity.METACLASS, "Outgoing")       : (Entity.METAASSOC,    Entity.METAASSOC,    "Name", DataFromEntity),
        (Entity.METACLASS, "OutgoingClasses"): (Entity.METACLASS,    Entity.METAASSOC,    "Name", DataFromTarget),
        (Entity.METACLASS, "Incoming")       : (Entity.METAASSOC,    Entity.METAASSOC,    "Name", DataFromEntity),
        (Entity.METACLASS, "IncomingClasses"): (Entity.METACLASS,    Entity.METAASSOC,    "Name", DataFromSource),
        (Entity.METAASSOC, "MetaProperties") : (Entity.METAPROPERTY, Entity.METAPROPERTY, "Name", DataFromEntity),
        (Entity.METACLASS, "MetaProperties") : (Entity.METAPROPERTY, Entity.METAPROPERTY, "Name", DataFromEntity),
        (Entity.METACLASS, "Extension")      : (Entity.CLASS,        Entity.CLASS,        "Id",   DataFromEntity),
        (Entity.METAASSOC, "Extension")      : (Entity.ASSOC,        Entity.ASSOC,        "Id",   DataFromEntity),
        (Entity.CLASS,     "Outgoing")       : (Entity.ASSOC,        Entity.ASSOC,        "Id",   DataFromEntity),
        (Entity.CLASS,     "Incoming")       : (Entity.ASSOC,        Entity.ASSOC,        "Id",   DataFromEntity),
        (Entity.CLASS,     "OutgoingClasses"): (Entity.CLASS,        Entity.ASSOC,        "Id",   DataFromTarget),
        (Entity.CLASS,     "IncomingClasses"): (Entity.CLASS,        Entity.ASSOC,        "Id",   DataFromSource),
        (Entity.METAMODEL, "Properties")     : (Entity.METAMODEL,    Entity.METAMODEL,    "Name", DataFromEntity),
        (Entity.METAENUM,  "Properties")     : (Entity.METAENUM,     Entity.METAENUM,     "Name", DataFromEntity),
        (Entity.METACLASS, "Properties")     : (Entity.METACLASS,    Entity.METACLASS,    "Name", DataFromEntity),
        (Entity.METAASSOC, "Properties")     : (Entity.METAPROPERTY, Entity.METAPROPERTY, "Name", DataFromEntity),
        (Entity.CLASS,     "Properties")     : (Entity.ASSOC,        Entity.ASSOC,        "Id",   DataFromEntity),
        (Entity.ASSOC,     "Properties")     : (Entity.ASSOC,        Entity.ASSOC,        "Id",   DataFromEntity)
    }

    def __init__(self, model, root = None, navigator = "", selector = "", editMode = ModeView):
        QObject.__init__(self)
        self.viewData = {}       # original source list to display
        self.keys = []           # mapping row -> item
        self.headers = []        # header names
        self.model = model
        self.root = None
        self.connected = 0
        self.reverse = {}        # mapping item id/name -> row
        self.editMode = editMode
        self.navigator = ""
        self.dataSelection = Table.DataFromEntity
        self._isNavigating = 0
        if root:
            self.navigate(root, navigator, selector)

    def navigate(self, root, navigator = "", selector = ""):
        #print "navigate", id(self), self.navigator, self.root
        self._isNavigating = 1
        assert(root)
        r = root.metaModel()
        if not self.connected:
            if r.watcher:
                for listener in r.watcher.listeners().itervalues():
                    if isinstance(listener, Emitter):
                        #print "connected:", type(root), navigator, selector
                        self.connected = 1
                        self.connect(listener, SIGNAL("propertyChanged"), 
                                     self.model_propertyChanged)
                        self.connect(listener, SIGNAL("entityCreated"), 
                                     self.model_entityCreated)
                        self.connect(listener, SIGNAL("entityDeleted"), 
                                     self.model_entityDeleted)
        assert(r.watcher)
        #assert(r.watcher.emitter)
        assert(self.connected)
        self.reverse = {}
        self.root = root
        self.navigator = navigator
        self.selector = selector
        self.viewDesc = Table.viewDescTable[ (root.typ(), navigator) ]

        self.dataSelection = self.viewDesc[3]
        self.identifyingProperty = self.viewDesc[2]

        if root.isMetaModel():
            if navigator == "MetaClasses":
                self.viewData = root.metaClasses
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description"]
            elif navigator == "MetaAssocs":
                self.viewData = root.metaAssocs
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description", 
                                 "SourceCardinality", "TargetCardinality", "Aggregation" ]
            elif navigator == "MetaTypes":
                self.viewData = root.metaTypes
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description", "DefaultValue" ]
            elif navigator == "Properties":
                self._setPropertyModel(root)

        elif root.isMetaClass():
            if navigator == "Extension":
                self.viewData = root.extension
                self.keys = self.viewData.keys()
                self.headers = root.metaProperties.keys()
            elif navigator == "MetaProperties":
                self.viewData = root.metaProperties
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "Outgoing":
                self.viewData = root.outgoing
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "OutgoingClasses":
                self.viewData = root.outgoing
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "Incoming":
                self.viewData = root.incoming
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "IncomingClasses":
                self.viewData = root.incoming
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "Properties":
                self._setPropertyModel(root)

        elif root.isMetaAssoc():
            if navigator == "Extension":
                self.viewData = root.extension
                self.keys = self.viewData.keys()
                self.headers = root.metaProperties.keys()
            elif navigator == "MetaProperties":
                self.viewData = root.metaProperties
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "Properties":
                self._setPropertyModel(root)

        elif root.isMetaEnum():
            if navigator == "MetaAtoms":
                self.viewData = root.metaAtoms
                self.keys = self.viewData.keys()
                self.headers = [ "Name", "Description" ]
            elif navigator == "Properties":
                self._setPropertyModel(root)

        elif root.isClass():
            if navigator == "Outgoing":
                self.viewData = root.outgoing[selector]
                self.keys = self.viewData.keys()
                targetMetaEntity = root.intention.outgoing[selector]
                self.headers = targetMetaEntity.metaProperties.keys()
            elif navigator == "OutgoingClasses":
                self.viewData = root.outgoing[selector]
                self.keys = self.viewData.keys()
                self.dataSelection = Table.DataFromTarget
                targetMetaEntity = root.intention.outgoing[selector].target
                self.headers = targetMetaEntity.metaProperties.keys()
            elif navigator == "Incoming":
                self.viewData = root.incoming[selector]
                self.keys = self.viewData.keys()
                targetMetaEntity = root.intention.incoming[selector]
                self.headers = targetMetaEntity.metaProperties.keys()
            elif navigator == "IncomingClasses":
                self.viewData = root.incoming[selector]
                self.keys = self.viewData.keys()
                self.dataSelection = Table.DataFromSource
                targetMetaEntity = root.intention.incoming[selector].source
                self.headers = targetMetaEntity.metaProperties.keys()
            elif navigator == "Properties":
                self._setPropertyModel(root)

        elif root.isAssoc():
            if navigator == "Properties":
                self._setPropertyModel(root)

        # build reverse access list for fast update
        # Mapping between view object id/name and the displayed row
        if navigator != "Properties":
            itemIds = None
            if self.dataSelection == Table.DataFromTarget:
                itemIds = [item.target[self.identifyingProperty] 
                           for item in self.viewData.values()]
            elif self.dataSelection == Table.DataFromSource:
                itemIds = [item.source[self.identifyingProperty] 
                           for item in self.viewData.values()]
            keyItemIds = [item[self.identifyingProperty] 
                          for item in self.viewData.values()]

            # enumerate just all keys from 0 to len of table
            rows = range(0, len(self.keys))
            self.reverse = dict(zip(keyItemIds, rows))
            assert(len(self.reverse) == len(self.viewData))
            if itemIds:
                # for view OutgoingClasses we need also the keys for the classes
                self.reverse.update(dict(zip(itemIds, rows)))
            #print "new", navigator, self.reverse
            assert(len(self.viewData) == len(keyItemIds))
            assert(len(rows) == len(self.viewData))
            #print navigator, self.reverse

        # User friendly
        if "Name" in self.headers:
            self.headers.remove("Name")
            self.headers.insert(0, "Name")
        if "Id" in self.headers:
            self.headers.remove("Id")
            self.headers.insert(0, "Id")

        self.model.reset()
        self._isNavigating = 0
        #print "navigate end", self.navigator, self.root

    def columnCount(self):
        return len(self.headers)

    def data(self, index, role):
        if role == Qt.DisplayRole or role == Qt.EditRole:
            if self.navigator == "Properties":
                key = self.keys[index.row()]
                if index.column() == 0:
                    return QVariant(key)
                else:
                    item = index.internalPointer()
                    assert(item)
                    assert(item == self.root)
                    #return QVariant(item[key])
                    return QVariant(UiTypes.asTextValue(item, key))
            else:
                if self._isExtendRow(index.row()):
                    return QVariant()
                else:
                    item = index.internalPointer()
                    if item:
                        if self.dataSelection == Table.DataFromSource:
                            item = item.source
                        elif self.dataSelection == Table.DataFromTarget:
                            item = item.target
                        header = self.headers[index.column()]
                        return QVariant(UiTypes.asTextValue(item, header))
        elif role == Table.KeyDataRole:
            if self.navigator == "Properties":
                return self.root
            elif self._isExtendRow(index.row()):
                return None
            else:
                item = index.internalPointer()
                return item
        elif role == Table.ViewDataRole:
            if self.navigator == "Properties":
                return self.root
            elif self._isExtendRow(index.row()):
                return None
            else:
                item = index.internalPointer()
                if item:
                    if self.dataSelection == Table.DataFromSource:
                        item = item.source
                    elif self.dataSelection == Table.DataFromTarget:
                        item = item.target
                    return item
            return None
        return QVariant()

    def setData(self, index, value, role):
        result = 0
        if role == Qt.EditRole:
            if self.navigator == "Properties":
                key = self.keys[index.row()]
                if index.column() == 1:
                    item = index.internalPointer()
                    assert(item)
                    self._setData(item, key, value)
                    result = 1
            else:
                if self._isExtendRow(index.row()):
                    self._createEntity(value, index)
                else:
                    item = index.internalPointer()
                    assert(item)
                    if self.dataSelection == Table.DataFromSource:
                        item = item.source
                    elif self.dataSelection == Table.DataFromTarget:
                        item = item.target
                    header = self.headers[index.column()]
                    self._setData(item, header, value)
                    result = 1
        return result

    def headerData(self, section, role):
        if self._isNavigating:
            return QVariant()
        try:
            if role == Qt.DisplayRole:
                return QVariant(self.headers[section])
            return QVariant()
        except:
            print "!exc", id(self), self.navigator, self.root, self._isNavigating
            return QVariant()

    def index(self, row, column, parent = None):
        if parent:
            if parent.isValid():
                pass
            else:
                # Top level items!
                if self.navigator == "Properties":
                    item = self.root
                else:
                    if self._isExtendRow(row):
                        return self.model.createIndex(row, column, None)
                    else:
                        key = self.keys[row]
                        item = self.viewData[key]   # Get whole view data item into index!
                return self.model.createIndex(row, column, item)
        return QModelIndex()

    def parent(self, index):
        return QModelIndex()

    def rowCount(self, parent = None):
        if self.editMode == Table.ModeExtend:
            return len(self.viewData) + 1
        else:
            return len(self.viewData)

    def flags(self, index, currentFlags):
        if self.editMode == Table.ModeView:
             return currentFlags

        if self.navigator == "Properties":
            if index.column() != 0:
                header = self.keys[index.row()]
                if self.root.isExtensionEntity():
                    if header != "Id":
                        currentFlags |= Qt.ItemIsEditable            
        else:
            if index.column() != 0:
                currentFlags |= Qt.ItemIsEditable

        return currentFlags

    def getIndexOf(self, repObject):
        if repObject:
            if self.navigator != "Properties":
                if self._maybeViewed(repObject):
                    row = self.reverse.get(repObject[self.identifyingProperty], -1)
                    if row != -1:
                        return self.index(row, 1, QModelIndex())
        return QModelIndex()
    
    def model_propertyChanged(self, repObject, key, oldValue, newValue):
        #print "model_propertyChanged", key, oldValue, "->", newValue
        if self.navigator == "Properties":
            if self.root == repObject:
                row = self.keys.index(key)
                col = 1
                self._emitChanged(row, col)

        elif self._maybeViewed(repObject):
            row = self.reverse.get(repObject[self.identifyingProperty], -1)
            if row != -1:
                col = self.headers.index(key)
                self._emitChanged(row, col)
          
    def model_entityCreated(self, repObject):
        #print "model_entityCreated"
        if self.navigator == "Properties":
            return

        if repObject.isMetaEntity() or repObject.isExtensionEntity():
            if self._isKeyObject(repObject):
                id = repObject[self.identifyingProperty]
                lastRow = self.rowCount()
                self.model.beginInsertRows(QModelIndex(), lastRow, lastRow)
                self.keys.append(id)
                self.viewData[id] = repObject
                self.reverse[id] = lastRow - 1
                if self.dataSelection == Table.DataFromTarget:
                    targetId = repObject.target[self.identifyingProperty]
                    self.reverse[targetId] = lastRow - 1
                elif self.dataSelection == Table.DataFromSource:
                    sourceId = repObject.source[self.identifyingProperty]
                    self.reverse[sourceId] = lastRow - 1
                self.model.endInsertRows()
                #print "EC", id, self.reverse

    def model_entityDeleted(self, repObject):
        if self.navigator == "Properties":
            return

        if repObject.isMetaEntity() or repObject.isExtensionEntity():
            if self._isKeyObject(repObject):
                id = repObject[self.identifyingProperty]
                row = self.reverse[id]

                self.model.beginRemoveRows(QModelIndex(), row, row)
                self.keys.remove(id)
                self.viewData.remove(id)
                self.reverse.pop(id)
                if self.dataSelection == Table.DataFromTarget:
                    targetId = repObject.target[self.identifyingProperty]
                    self.reverse.pop(targetId)
                elif self.dataSelection == Table.DataFromSource:
                    sourceId = repObject.source[self.identifyingProperty]
                    self.reverse.pop(sourceId)

                # correct all stored rows in reverse list
                for k,v in self.reverse.items():
                    if v > row:
                        self.reverse[k] = v - 1
                self.model.endRemoveRows()

    def _setData(self, item, key, value):
        item[key] = self._setData2(item.intention.metaProperties[key], value)

    def _setData2(self, mp, value):
        if isinstance(value, QString):
            return getTypedValue(mp.metaType, str(value))
        elif isinstance(value, QVariant):
            return getTypedValue(mp.metaType, str(value.toString()))
        else:
            return getTypedValue(mp.metaType, value)

    def _setPropertyModel(self, root):
        self.viewData = root
        self.keys = root.keys()
        self.headers = ["Name", "Value"]

    def _emitChanged(self, row, col):
        index = self.index(row, col)
        self.model.emit(SIGNAL("dataChanged(const QModelIndex&, const QModelIndex&)"),
                        index, index)

    def _maybeViewed(self, repObject):
        result = 0

        # Entity type is viewed!
        viewedType = self.viewDesc[0]  
        if viewedType == repObject.typ():
            if self.navigator == "Extension":
                if self.root["Name"] == repObject.intention["Name"]:
                    result = 1
            elif (self.navigator == "Outgoing" and viewedType == Entity.ASSOC):
                if self.selector == repObject.intention["Name"]:
                    result = 1
            elif (self.navigator == "Incoming" and viewedType == Entity.ASSOC):
                if self.selector == repObject.intention["Name"]:
                    result = 1
            elif (self.navigator == "OutgoingClasses" and viewedType == Entity.CLASS or
                  self.navigator == "IncomingClasses" and viewedType == Entity.CLASS):
                assocNameParts = self.selector.split(".")
                metaClassName = repObject.intention["Name"]
                if ( self.navigator == "OutgoingClasses" and 
                     metaClassName == assocNameParts[2] ):
                    result = 1
                elif ( self.navigator == "IncomingClasses" and 
                       metaClassName == assocNameParts[0] ):
                    result = 1
            else:
                return 1

        return result

    def _isKeyObject(self, repObject):
        result = 0

        # Entity type is used as key
        keyType = self.viewDesc[1]  
        if keyType == repObject.typ():
            if self.navigator == "Extension":
                if self.root["Name"] == repObject.intention["Name"]:
                    result = 1
            elif (self.navigator == "Outgoing"        and keyType == Entity.ASSOC or
                  self.navigator == "OutgoingClasses" and keyType == Entity.ASSOC):
                if self.selector == repObject.intention["Name"]:
                    if repObject.source == self.root:
                        result = 1
            elif (self.navigator == "Incoming"        and keyType == Entity.ASSOC or
                  self.navigator == "IncomingClasses" and keyType == Entity.ASSOC):
                if self.selector == repObject.intention["Name"]:
                    if repObject.target == self.root:
                        result = 1
            else:
                result = 1

        return result

    def _isExtendRow(self, row):
        if self.editMode == Table.ModeExtend:
            if row == len(self.viewData):
                #print row, self.viewData
                return 1
        return 0

    def _createEntity(self, value, index):
        assert(self.editMode == Table.ModeExtend)
        if (self.root.typ() == Entity.CLASS and 
            (self.navigator == "OutgoingClasses" or
             self.navigator == "IncomingClasses")):
            r = self.root.metaModel()
            ma = r.metaAssocs[self.selector]

            header = self.headers[index.column()]
            if self.navigator == "OutgoingClasses":
                mp = ma.target.metaProperties[header]
            else:
                mp = ma.source.metaProperties[header]
            values = self._getInitProperties(mp, value)
            for val in values:
                if self.navigator == "OutgoingClasses":
                    cls = r.Class(ma.target["Name"])
                    cls[header] = self._setData2(mp, val)
                    a = r.Assoc(self.root, cls, ma["Name"])
                else:
                    cls = r.Class(ma.source["Name"])
                    cls[header] = self._setData2(mp, val)
                    a = r.Assoc(cls, self.root, ma["Name"])

        elif (self.root.typ() == Entity.METACLASS and
              self.navigator == "Extension"):
            r = self.root.metaModel()
            header = self.headers[index.column()]
            mp = self.root.metaProperties[header]
            values = self._getInitProperties(mp, value)
            for val in values:
                cls = r.Class(self.root["Name"])
                assert(cls)
                cls[header] = self._setData2(mp, val)
        else:
            # not implemented
            assert(0)

    def _getInitProperties(self, mp, value):
        if mp["Name"] == "Name":
            name = str(value.toString())
            names = name.split(";")
            return names
        else:
            #return [str(value.toString())]
            return [value]

        
class TableModel(QAbstractItemModel):
    
    def __init__(self, parent=None):
        QAbstractItemModel.__init__(self, parent)
        self._table = None

    def setTable(self, newTable):
        self._table = newTable
    def table(self):
        return self._table
    
    def columnCount(self, parent):
        return self._table.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        return self._table.data(index, role)

    def setData(self, index, value, role):
        if not index.isValid():
            return QVariant()
        return self._table.setData(index, value, role)

    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal:
             return self._table.headerData(section, role)
        return QVariant()

    def index(self, row, column, parent = QModelIndex()):
        return self._table.index(row, column, parent)

    def rowCount(self, parent):
        return self._table.rowCount(parent)
    
    def flags(self, index):
        flags = QAbstractItemModel.flags(self, index)
        flags = self._table.flags(index, flags)
        return flags

    def parent(self, index):
        return self._table.parent(index)



class RepositoryTableView(QTableView):
    def __init__(self, root, navigator, selector = "", editMode = Table.ModeView, parent = None):
        QTableView.__init__(self, parent)
        self.setSelectionMode(QTableView.SingleSelection)
        self.setSelectionBehavior(QTableView.SelectRows)
        self.verticalHeader().setDefaultSectionSize(22)

        model = TableModel()
        table = Table(model, root, navigator, selector, editMode)
        self.setItemDelegate(Delegate(table, self))
        model.setTable(table)
        self.setModel(model)

        if navigator == "Properties":
            for i in range(table.rowCount()):
               idx = table.index(i, 1)
               self.openPersistentEditor(idx)

    def setCurrentItem(self, repObject):
        idx = self.model().table().getIndexOf(repObject)
        if idx.isValid():
            self.setCurrentIndex(idx)
        return idx

    def contextMenuEvent(self, e):
        idx = self.currentIndex()
        ob = self.model().data(idx, Table.ViewDataRole)
        if ob:
            if ob.isClass():
                menu = QMenu(self)
                self.deleteAction = QAction("Delete item", self)
                menu.addAction(self.deleteAction)
                self.connect(self.deleteAction, SIGNAL("triggered(bool)"), 
                             self._deleteItem)
                menu.popup(self.mapToGlobal(e.pos()))

    def _deleteItem(self):
        idx = self.currentIndex()
        ob = self.model().data(idx, Table.ViewDataRole)
        if ob:
            ob.metaModel().deleteClass(ob)

class EnumComboBox(QComboBox):
    def __init__(self, entity, property, parent = None):
        QComboBox.__init__(self, parent)
        assert(entity.isExtensionEntity())
        self.entity = entity
        self.property = property
        mp = entity.intention.metaProperties[property]
        me = mp.metaType
        assert(me.isMetaEnum)
        self.setModelColumn(0)
        model = TableModel()
        table = Table(model, me, "MetaAtoms", "", Table.ModeView)
        model.setTable(table)
        self.setModel(model)
        self.setModelColumn(0)

        #idx = self.findText(entity[property])
        #self.setCurrentIndex(idx)

        self.connect(self, SIGNAL("activated(const QString &)"), 
                     self.combo_activated) 

    def combo_activated(self, text):
        #self.entity[self.property] = str(text)
        pass
    
    def setEditorData(self, value):
        idx = self.findText(value)
        self.setCurrentIndex(idx)
    def getEditorData(self):
        return str(self.currentText())

class ReferenceComboBox(QWidget):
    def __init__(self, root, metaAssoc, parent = None):
        # todo: Current only outgoing N1 assocs are possible
        QWidget.__init__(self, parent)

        self.combo = QComboBox(self)
        layout = QHBoxLayout(self)
        layout.addWidget(self.combo)

        # add button for deleting the reference
        if metaAssoc["TargetCardinality"] == OPTIONAL:
            button = QPushButton(QIcon("img/delete.png"), "")
            button.setFixedSize(QSize(20, 20))
            button.setFlat(True)
            button.connect(button, SIGNAL("clicked()"), 
                           self.deleteButtonClicked)
            layout.addWidget(button)

        button = QPushButton(QIcon("img/navigate.png"), "")
        button.setFixedSize(QSize(20, 20))
        button.setFlat(True)
        button.connect(button, SIGNAL("clicked()"), 
                       self.navigateButtonClicked)
        layout.addWidget(button)

            
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)
            
        self.root = root
        self.selector = metaAssoc["Name"]
        assoc = getFirst(root.outgoing[self.selector])

        self.combo.setModelColumn(1)
        model = TableModel()
        table = Table(model, metaAssoc.target, "Extension", "", Table.ModeView)
        model.setTable(table)
        self.combo.setModel(model)
        self.combo.setModelColumn(1)

        self.combo.connect(self.combo, SIGNAL("activated(int)"), 
                           self.combo_activated) 
        self.currentSelected = None
        if assoc == None:
            self.combo.setCurrentIndex(-1)
        else:
            self.currentSelected = assoc.target
            idx = table.reverse[self.currentSelected["Id"]]
            self.combo.setCurrentIndex(idx)

    def combo_activated(self, idx):
        #print "new index " , idx
        table = self.combo.model().table()
        
        #todo: no good solution
        #newSelected = table.viewData[table.keys[idx]][0]
        newSelected = table.viewData[table.keys[idx]]  
        if newSelected != self.currentSelected:
            r = self.root.metaModel()
            if self.currentSelected:
                # don't change assoc: delete it
                assoc = getFirst(self.root.outgoing[self.selector])
                r.deleteAssoc(assoc)

            # and create a new one
            r.Assoc(self.root, newSelected, self.selector)
            idx = table.reverse[newSelected["Id"]]
            self.combo.setCurrentIndex(idx)
            self.currentSelected = newSelected

    def navigateButtonClicked(self):
        self.emit(SIGNAL("navigateRequest"), self.currentSelected)

    def deleteButtonClicked(self):
        #print "deleteButtonClicked"
        idx = self.combo.currentIndex()
        if idx != -1:
            #print "deleteButtonClicked 1"
            table = self.combo.model().table()
            newSelected = table.viewData[table.keys[idx]]  
            if newSelected:
                #print "deleteButtonClicked 2"
                r = self.root.metaModel()
                # don't change assoc: delete it
                assoc = getFirst(self.root.outgoing[self.selector])
                r.deleteAssoc(assoc)
                self.currentSelected = None
                self.combo.setCurrentIndex(-1)
    
class PropertyDialog(QDialog):
    def __init__(self, repObject, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle("Properties")
        view = RepositoryTableView(repObject, "Properties", "", Table.ModeEdit)
        layout = QGridLayout(self)
        layout.addWidget(view, 0, 0)
        self.resize(250, 300)
        self.setLayout(layout)
        self.setWindowIcon(QIcon("img/spiderIco.png"))

class MatrixWidget(QDialog):
    def __init__(self, rep, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle("MatrixWidget")
        self.repository = rep
        self.currentDirection = "OutgoingClasses"
        self.currentMetaAssoc = ""

        # 1. MetaClass View
        self.metaClassView = RepositoryTableView(rep, "MetaClasses", "", Table.ModeView, self)

        # 2. Class view
        self.classView = RepositoryTableView(None, "", "", Table.ModeExtend, self)

        # 3a. MetaAssoc Outgoing view
        self.metaAssocOutView = RepositoryTableView(None, "", "", Table.ModeView, self)

        # 3b. MetaAssoc Incoming view
        self.metaAssocInView = RepositoryTableView(None, "", "", Table.ModeView, self)

        # 4. TargetClass view
        self.targetClassView = RepositoryTableView(None, "", "", Table.ModeExtend, self)
     
        metaAssocLayout = QVBoxLayout()
        metaAssocLayout.addWidget(self.metaAssocOutView)
        metaAssocLayout.addWidget(self.metaAssocInView)

        layout = QGridLayout(self)
        layout.addWidget(self.metaClassView, 0, 0)
        layout.addWidget(self.classView, 1, 0)
        layout.addLayout(metaAssocLayout, 0, 1)
        layout.addWidget(self.targetClassView, 1, 1)
        layout.setRowStretch(0,8)
        layout.setRowStretch(1,10)
        self.setLayout(layout)

        # Connect all together
        self.connect(self.metaClassView, SIGNAL("clicked(const QModelIndex &)"), 
                     self.metaClassView_clicked)
        self.connect(self.classView, SIGNAL("clicked(const QModelIndex & )"), 
                     self.classView_clicked)
        self.connect(self.classView.selectionModel(), 
                     SIGNAL("currentChanged(const QModelIndex &, const QModelIndex & )"), 
                     self.classView_currentChanged)
        self.connect(self.metaAssocOutView, SIGNAL("clicked(const QModelIndex & )"), 
                     self.metaAssocOutView_clicked)
        self.connect(self.metaAssocInView, SIGNAL("clicked(const QModelIndex & )"), 
                     self.metaAssocInView_clicked)
        self.connect(self.targetClassView, SIGNAL("doubleClicked(const QModelIndex & )"), 
                     self.targetClassView_doubleClicked)
        self.connect(self.classView, SIGNAL("doubleClicked(const QModelIndex & )"), 
                     self.classView_doubleClicked)
        self.setWindowIcon(QIcon("img/spiderIco.png"))

    def metaClassView_clicked(self, index):
        #print "metaClassView_clicked"
        table = self.classView.model().table()
        repObject = table.data(index, Table.ViewDataRole)
        if not repObject:
            return
        table.navigate(repObject, "Extension")
        table = self.metaAssocOutView.model().table()
        table.navigate(repObject, "Outgoing")
        table = self.metaAssocInView.model().table()
        table.navigate(repObject, "Incoming")

        # Select second in assoc out or in view
        idx = self.metaAssocOutView.model().index(0,0)
        if idx.isValid():
            self.metaAssocOutView.setCurrentIndex(idx)
            self.metaAssocOutView_clicked(idx)
        else:
            idx = self.metaAssocInView.model().index(0,0)
            if idx.isValid():
                self.metaAssocInView.setCurrentIndex(idx)
                sm.select(idx, QItemSelectionModel.SelectCurrent)
                self.metaAssocInView_clicked(idx)

        # Select first in class view
        idx = self.classView.model().index(0,0)
        if idx.isValid():
            self.classView.setCurrentIndex(idx)
            currentIndex = self.classView.currentIndex()
            self.updateTargetClassView()


    def updateTargetClassView(self):
        #print "updateTargetClassView"
        table = self.targetClassView.model().table()
        currentIndex = self.classView.currentIndex()
        if currentIndex:
            if self.currentDirection == "OutgoingClasses":
                item = currentIndex.internalPointer()
                if item:
                    table.navigate(item, self.currentDirection, 
                                   self.currentMetaAssoc)
            elif self.currentDirection == "IncomingClasses":
                item = currentIndex.internalPointer()
                if item:
                    table.navigate(item, self.currentDirection, 
                                   self.currentMetaAssoc)
        
    def classView_clicked(self, index):
        #print "classView_clicked"
        self.updateTargetClassView()

    def classView_doubleClicked(self, index):
        table = self.classView.model().table()
        item = table.data(index, Table.ViewDataRole)
        dialog = PropertyDialog(item)
        dialog.exec_()
        
    def classView_currentChanged(self, current, previous):
        print "classView_currentChanged"
        self.updateTargetClassView()

    def metaAssocOutView_clicked(self, index):
        print "metaAssocOutView_clicked"
        table = self.metaAssocOutView.model().table()
        item = table.data(index, Table.KeyDataRole)
        self.currentMetaAssoc = item["Name"]
        self.currentDirection = "OutgoingClasses"
        self.updateTargetClassView()

    def metaAssocInView_clicked(self, index):
        print "metaAssocInView_clicked"
        table = self.metaAssocInView.model().table()
        item = table.data(index, Table.KeyDataRole)
        self.currentMetaAssoc = item["Name"]
        self.currentDirection = "IncomingClasses"
        self.updateTargetClassView()

    def targetClassView_doubleClicked(self, index):
        # Get class
        table = self.targetClassView.model().table()
        item = table.data(index, Table.KeyDataRole)
        if self.currentDirection == "OutgoingClasses":
            item = item.target
        elif self.currentDirection == "IncomingClasses":
            item = item.source
        else:
            assert(0)

        # get MetaClass
        mc = item.intention

        # Select meta class in MetaClassView
        mcIndex = self.metaClassView.setCurrentItem(mc)
        #mcTable = self.metaClassView.model().table()
        #mcRow = mcTable.keys.index(mc["Name"])
        #mcIndex = mcTable.index(mcRow, 0)
        self.metaClassView_clicked(mcIndex)        

        # Select class in ClassView
        cTable = self.classView.model().table()
        cRow = cTable.keys.index(item["Id"])
        cIndex = cTable.index(cRow, 0)
        self.classView.setCurrentIndex(cIndex)
        if self.currentDirection == "IncomingClasses":
            self.currentDirection = "OutgoingClasses"
        else:
            self.currentDirection = "IncomingClasses"        
        self.classView_clicked(cIndex)        

class MatrixBrowser(Component.Component):
    def __init__(self):
        Component.Component.__init__(self)

    def interface(self, interfaceName):
        if interfaceName == "Spider.IProject":
            return self
        elif interfaceName == "Spider.IManagedComponent":
            return self
        return None

    # Interface Spider.IProject
    def open(self, project, r, item):
        self.project = project
        self.projectItem = item
        self.mb = MatrixWidget(r)
        self.mb.show()

    # Interface Spider.IManagedComponent
    @staticmethod
    def setupComponentType(rSpiderCOMP):
        return Component.Component._setupComponentType(rSpiderCOMP, "Spider.Ui.MatrixBrowser",
                                                       "Shows a metamodel in a grid",
                                                       1, ["Spider.IProject", "Spider.IManagedComponent"])

def _demoMatrix():
    iniComp = Component.IniFileReader()
    iniComp.read("xtcpmon.ini")
    mmc = Component.MetaModelConverter()
    rMMM = mmc.extract(iniComp.repository)
    rMMM.watcher = Watcher()
    rMMM.watcher.addListener(Emitter(), "Emitter")

    rFile = mmc.instantiiate(rMMM)
    mw = MatrixWidget(rMMM)
    mw.exec_()
    #app.exec_()

def _demoRep():
    r = DefaultRep()
    r.watcher.addListener(Emitter(), "Emitter")
    mw = MatrixWidget(r)
    mw.exec_()
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    #s = { "a":"b" }
    #QtGui.QMessageBox.critical(None, s["a"],
    #                           "Unable to start the test: %1.")

    #di = Component.DirectoryImporter()
    #di.read("C:\\Windows", "")
    
    #_demoMatrix()
    _demoRep()
    
    sys.exit(0)

#>>> l = QLabel()
#>>> l.setPixmap(pix)
#>>> l.show()
#>>> bytes = QByteArray()
#>>> buffer = QBuffer(bytes)
#>>> buffer
#<PyQt4.QtCore.QBuffer object at 0x009B2BB8>
#>>> buffer.open(QIODevice.WriteOnly)
#True
#>>> pix.save(buffer, "PNG")
#True
#>>> buffer
#<PyQt4.QtCore.QBuffer object at 0x009B2BB8>
#>>> bytes
#<PyQt4.QtCore.QByteArray object at 0x009B2B70>
#>>> bytes.data()
#'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x1e\x00\x00\x00\x1e\x08\x02\x00
#\x00\x00\xb4R9\xf5\x00\x00\x00\tpHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\x01\x95+\x0
#e\x1b\x00\x00\x00]IDATH\x89\xed\x92A\n\xc0@\x0c\x02\xb5\xf4\xff_N\x0fR\xa1\xd0K!
#)\x08\xf1\xb2b ,c\x88\x01U\x15\x80S\xbeu3\xf5\x1c\xadK\x1f\x1a\\\xad\xcf/\x90?D\
#xdcg\xf8>&\xbfN\xc9h\xd6[\xa3C\x99L\xd6[\xa3C\x99L\xd6[\xa3C\x99L\xd6\xa15\xba\x
#07\xe3\xef\xd2 \x90\x0b8\x0f,+;\xf2\xa7y\x00\x00\x00\x00IEND\xaeB`\x82'
#>>> type(bytes.data())
#<type 'str'>

#        current = item[key]
#        if isinstance(current, int):
#           if isinstance(value, int):
#               item[key] = value
#           else:
#               s = str(value.toString())
#               if s == "true" or s == "1":
#                   item[key] = 1
#               else:
#                   item[key] = 0
#        elif isinstance(current, tuple):
#           if isinstance(value, tuple):
#               item[key] = value
#           else:
#               assert(0)
#        elif isinstance(current, float):
#           if isinstance(value, float):
#               item[key] = value
#           else:
#               item[key] = float(str(value.toString()))
#        elif isinstance(current, str) or isinstance(current, unicode):
#           if isinstance(value, str):
#               item[key] = value
#           elif isinstance(value, tuple):
#               item[key] = str(value)
#           else:
#               item[key] = str(value.toString())
#        else:
#            print current, type(current)
#            assert(0)##
